﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIObjects.TreeViewInterfaces;
#if SILVERLIGHT
using AbstraX.ClientInterfaces;
#else
using AbstraX.ServerInterfaces;
#endif
using System.Collections.ObjectModel;
using AbstraX.Contracts;
using MvvmTreeView;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.ServiceModel.DomainServices.Client;
using System.Windows.Controls;
using System.ComponentModel;
using UIObjects.DragDropInterfaces;

namespace AbstraX.ViewModels.ModelTree
{
    [TreeNode(typeof(ModelTreeNodeBase), "")]
    public abstract class ModelTreeNodeBase : ITreeNode
    {
        protected IProviderClientService providerService;
        protected TreeNodeCollection nodes;
        protected ITreeView treeView;
        protected bool isExpanded;
        protected bool isChildrenLoaded;
        protected bool allowDrop;
        protected bool hasChildrenQueried;
        protected IAbstraXExtension abstraXExtension;
        public virtual event ImageAvailableHandler ImageAvailable;
        public event PropertyChangedEventHandler PropertyChanged;
        public event ImageAvailableHandler GlyphAvailable;
        public event ImageAvailableHandler LayoverImageAvailable;
        public object TreeViewItem { get; set; }

        public ModelTreeNodeBase(IProviderClientService providerService, ITreeView treeView)
        {
            this.treeView = treeView;
            this.providerService = providerService;

            nodes = new TreeNodeCollection();
        }

        [TreeNodeProperty(TreeNodePropertyType.Text)]
        public abstract string Text { get; set; }
        public abstract void LoadChildren();
        protected abstract void ChildrenLoaded(IBase parent);
        public abstract List<string> AddNewShortCuts { get; }
        public object ItemContent { get; set; }
        public abstract void AddNew(string shortCut);
        public abstract void DragStarting(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e);
        public abstract void DragCompleted(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e);
        public abstract void ItemDropped(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e, int insertionIndex);
        public abstract void GiveFeedback(object sender, GiveFeedbackEventArgs e);
        public abstract void DragEnter(object sender, UIObjects.DragDropInterfaces.DragEventArgs e);
        public abstract void DragLeave(object sender, UIObjects.DragDropInterfaces.DragEventArgs e);
        public abstract void DragOver(object sender, UIObjects.DragDropInterfaces.DragEventArgs e);
        public abstract float ChildOrdinal { get; set; }
        public abstract bool? HasChildren { get; }
        public abstract IBase BaseObject { get; }
        public abstract void OnSelect();

        public bool IsChildrenLoaded
        {
            get
            {
                return isChildrenLoaded;
            }
        }

        public object BackColor
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public object Bounds
        {
            get { throw new NotImplementedException(); }
        }

        public bool Checked
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public ITreeNode FirstNode
        {
            get { throw new NotImplementedException(); }
        }

        public string FullPath
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsEditing
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsExpanded
        {
            get 
            {
                return isExpanded;
            }
        }

        public bool IsSelected
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsVisible
        {
            get { throw new NotImplementedException(); }
        }

        public ITreeNode LastNode
        {
            get { throw new NotImplementedException(); }
        }

        public int Level
        {
            get { throw new NotImplementedException(); }
        }

        public ITreeNode NextNode
        {
            get { throw new NotImplementedException(); }
        }

        public ITreeNode NextVisibleNode
        {
            get { throw new NotImplementedException(); }
        }

        public void RemoveSpinster()
        {
            if (this.ContainsSpinster)
            {
                var treeViewItem = (TreeViewItem)this.TreeViewItem;
                var spinsterNode = (SpinsterNode) treeViewItem.Items.Cast<ITreeNode>().Where(n => n is SpinsterNode).Select(s => s).First();

                isExpanded = true;
                nodes.Remove(spinsterNode);

                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Children"));
            }
        }

        public bool ContainsSpinster
        {
            get
            {
                if (this.TreeViewItem != null)
                {
                    return ((TreeViewItem)this.TreeViewItem).Items.Cast<ITreeNode>().Any(n => n is SpinsterNode);
                }
                else
                {
                    return false;
                }
            }
        }

        [TreeNodeChildSource(typeof(ModelTreeNodeBase), DragDropEffects.Copy, "", "", "")]
        public virtual TreeNodeCollection Nodes
        {
            get 
            {
                if ((this.HasChildren ?? true) && (!this.ContainsSpinster) && (!this.IsChildrenLoaded))
                {
                    nodes.Add(new SpinsterNode(treeView));
                }

                return nodes;
            }
        }

        public ITreeNode Parent
        {
            get { throw new NotImplementedException(); }
        }

        public ITreeNode PrevNode
        {
            get { throw new NotImplementedException(); }
        }

        public ITreeNode PrevVisibleNode
        {
            get { throw new NotImplementedException(); }
        }

        public int SelectedImageIndex { get; set; }
        public string SelectedImageKey { get; set; }
        public int StateImageIndex { get; set; }
        public string StateImageKey { get; set; }
        public object Tag { get; set; }
        public int ImageIndex { get; set; }
        public string ImageKey { get; set; }

        public string ToolTipText
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public ITreeView TreeView
        {
            get 
            {
                return treeView;
            }
        }

        public void BeginEdit()
        {
            throw new NotImplementedException();
        }

        public object Clone()
        {
            throw new NotImplementedException();
        }

        public void Collapse()
        {
            throw new NotImplementedException();
        }

        public void Collapse(bool ignoreChildren)
        {
            throw new NotImplementedException();
        }

        public void EndEdit(bool cancel)
        {
            throw new NotImplementedException();
        }

        public void EnsureVisible()
        {
            throw new NotImplementedException();
        }

        public virtual void Expand()
        {
            if (!this.IsChildrenLoaded)
            {
                this.LoadChildren();
            }

            if (this.TreeViewItem != null)
            {
                ((TreeViewItem)this.TreeViewItem).IsExpanded = true;
                this.isExpanded = true;
            }
        }

        public virtual void ExpandAll()
        {
            this.Expand();
        }

        public int GetNodeCount(bool includeSubTrees)
        {
            throw new NotImplementedException();
        }

        public void Remove()
        {
            treeView.Nodes.Remove(this);
        }

        public void Toggle()
        {
            throw new NotImplementedException();
        }

        public virtual object Image
        {
            get
            {
                object tagObject = this.Tag;
                BitmapImage image = null;

                if (tagObject != null)
                {
                    var baseObject = this.BaseObject;
                    var imageUrl = baseObject.ImageURL;
                    var key = string.IsNullOrEmpty(imageUrl) ? tagObject.ToString() : imageUrl;

                    if (treeView.ImageList.Images.ContainsKey(key))
                    {
                        image = treeView.ImageList.Images[key];
                    }
                }

                return image;
            }
        }

        public virtual void StartLoadImage()
        {
            var tagObject = this.Tag;

            if (tagObject != null)
            {
                var baseObject = this.BaseObject;
                var imageUrl = baseObject.ImageURL;
                var key = string.IsNullOrEmpty(imageUrl) ? tagObject.ToString() : imageUrl;
                var imageList = treeView.ImageList;

                if (imageList.Images.ContainsKey(key))
                {
                    if (imageList.ImageLoadHandlers.ContainsKey(key))
                    {
                        var eventHandlers = imageList.ImageLoadHandlers[key];

                        foreach (ImageAvailableHandler handler in ImageAvailable.GetInvocationList())
                        {
                            eventHandlers.Add(handler);
                        }
                    }

                    ImageAvailable(this);
                }
                else
                {
                    if (imageList.ImageLoadHandlers.ContainsKey(key))
                    {
                        var eventHandlers = imageList.ImageLoadHandlers[key];

                        foreach (ImageAvailableHandler handler in ImageAvailable.GetInvocationList())
                        {
                            eventHandlers.Add(handler);
                        }
                    }
                    else
                    {
                        if (string.IsNullOrEmpty(imageUrl))
                        {
                            var operation = providerService.LoadImageForItemType(key);
                            operation.Completed += new EventHandler(LoadImage_Completed);
                        }
                        else
                        {
                            var itemType = baseObject.ToString(); 
                            var operation = providerService.LoadImageForUrl(itemType, imageUrl);
                            operation.Completed += new EventHandler(LoadImage_Completed);
                        }

                        imageList.ImageLoadHandlers.Add(key, new List<ImageAvailableHandler>());
                    }
                }
            }
        }

        protected void LoadImage_Completed(object sender, EventArgs e)
        {
            var baseObject = this.BaseObject;
            var imageUrl = baseObject.ImageURL;
            var tagObject = this.Tag;
            var key = string.IsNullOrEmpty(imageUrl) ? tagObject.ToString() : imageUrl;
            var invokeOperation = (InvokeOperation)sender;
            var imageData = (byte[])invokeOperation.Value;
            var imageList = treeView.ImageList;
            var eventHandlers = imageList.ImageLoadHandlers[key];

            imageList.Images.Add(key, imageData, Colors.Transparent);

            ImageAvailable(this);

            foreach (ImageAvailableHandler handler in eventHandlers)
            {
                handler(this);
            }
        }

        public virtual MvvmTreeView.ContextMenu ContextMenu
        {
            get
            {
                return null;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public ITreeNode ShallowClone()
        {
            throw new NotImplementedException();
        }

        public ITreeNode DeepClone()
        {
            throw new NotImplementedException();
        }

        public bool AllowRename
        {
            get
            {
                return false;
            }
        }

        public bool AllowDrop
        {
            get 
            {
                return false;
            }
        }

        public bool HasLayoverImage<T>(out T image)
        {
            throw new NotImplementedException();
        }

        public object Glyph
        {
            get { throw new NotImplementedException(); }
        }

        public object LayoverImage
        {
            get { throw new NotImplementedException(); }
        }

        public virtual string SelectionStatus
        {
            get
            {
                return null;
            }
        }
    }
}
